package com.threeti.mecool.web.assembler;

import com.threeti.mecool.core.domain.model.acl.PermissionRole;
import com.threeti.mecool.core.domain.model.acl.User;
import com.threeti.mecool.core.infrastructure.persistence.acl.PermRoleRepository;
import com.threeti.mecool.web.form.PermissionRoleForm;
import com.threeti.mecool.web.form.UserForm;
import com.threeti.mecool.web.util.DozerMapperSingleton;
import org.dozer.Mapper;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.util.Map;

public abstract class UserAssembler {
    public static UserForm toForm(User user) {
        Mapper transfer = DozerMapperSingleton.getInstance();
        UserForm destDto = new UserForm();
        transfer.map(user, destDto);
        return destDto;
    }

    public static User toDom(UserForm userForm) {
        Mapper transfer = DozerMapperSingleton.getInstance();
        User destDom = new User();
        transfer.map(userForm, destDom);
        return destDom;
    }

    public static User toDomWithPermissionEntries(UserForm userForm, PermRoleRepository permRoleRepo) {
        Mapper transfer = DozerMapperSingleton.getInstance();
        User destDom = new User();
        transfer.map(userForm, destDom);

        //jay:post eager fetch sample->
        PermissionRole permRolePostEagerFetched = permRoleRepo.findOneWithPermissionEntries(Long.valueOf(userForm.getRoleIdSlt()));
        destDom.setPermissionRole(permRolePostEagerFetched);
        //<-

        return destDom;
    }

    public static PermissionRole toDom(PermissionRoleForm form) {
        PermissionRole destDom = new PermissionRole();
        destDom.setId(Long.valueOf(form.getUpdatekey()));
        destDom.setName(form.getName());
        destDom.setPermissionEntries(form.getPermissionEntries());
        destDom.setManagedAdminDivisionCodeEntries(form.getManagedAdminDivisionCodeEntries());
        destDom.setManagedOrgCodeEntries(form.getManagedOrgCodeEntries());
        destDom.setAdvanced("1".equals(form.getIsAdvanced()));
        destDom.setUseADFilter(form.getUseADFilter());
        return destDom;
    }

    public static PermissionRoleForm toForm(PermissionRole permissionRole) {
        Mapper transfer = DozerMapperSingleton.getInstance();
        PermissionRoleForm destDto = new PermissionRoleForm();
        transfer.map(permissionRole, destDto);
        return destDto;
    }

    public static Specifications<User> toCriteria(Map<String, String> paramMap) {

        String loginName = paramMap.get("loginName");
        String displayName = paramMap.get("displayName");
        String roleId = paramMap.get("roleId");

        Specifications<User> spec = null;
        if (StringUtils.hasText(loginName)) {
            spec = likeLoginName(loginName);
        }

        if (StringUtils.hasText(displayName)) {
            if (spec == null) {
                spec = likeDisplayName(displayName);
            } else {
                spec = spec.and(likeDisplayName(displayName));
            }
        }

        if (StringUtils.hasText(roleId)) {
            try {
                Long roleIdNumber = Long.valueOf(roleId);
                if (spec == null) {
                    spec = eqRoleId(roleIdNumber);
                } else {
                    spec = spec.and(eqRoleId(roleIdNumber));
                }
            } catch (Exception e) {
            }
        }

        return spec;
    }

    private static Specifications<User> eqRoleId(final Long roleId) {
        return Specifications.where(new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                Path<Long> path = root.get("permissionRole").get("id");
                return builder.equal(path, roleId);
            }
        });
    }

    private static Specifications<User> likeDisplayName(final String displayName) {
        return Specifications.where(new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                Path<String> path = root.get("displayName");
                return builder.like(path, "%" + displayName + "%");
            }
        });
    }

    public static Specifications<User> likeLoginName(final String loginName) {
        return Specifications.where(new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                Path<String> loginNamePath = root.get("loginName");
                return builder.like(loginNamePath, "%" + loginName + "%");
            }
        });
    }

}
